package com.neusoft.databus.agent.pool.serial;

import java.io.IOException;

import org.apache.commons.pool2.PooledObject;
import org.springframework.stereotype.Component;

import com.neusoft.databus.common.connection.SerialConnection;
import com.neusoft.databus.common.pool.AbstractPoolFactory;

import gnu.io.CommPortIdentifier;
import gnu.io.NoSuchPortException;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.UnsupportedCommOperationException;
import lombok.extern.slf4j.Slf4j;

/**
 * serial port factory
 *
 * @author sunchf
 */
@Slf4j
@Component
public class SerialFactory extends AbstractPoolFactory<SerialConnection, SerialPort> {

    @Override
    public SerialPort create(final SerialConnection connection) {
        if (SerialFactory.log.isInfoEnabled()) {
            SerialFactory.log.info("start to create serial connection, {}", connection.getComValue());
        }
        SerialPort sPort = null;
        CommPortIdentifier commPortId = null;
        try {
            commPortId = CommPortIdentifier.getPortIdentifier(connection.getComValue());
        } catch (final NoSuchPortException e) {
            throw new RuntimeException("端口无效", e);
        }

        try {
            sPort = (SerialPort) commPortId.open(commPortId.getName(), connection.getConnectTimeout() < 100
                    ? connection.getConnectTimeout() * 1000 : connection.getConnectTimeout());
            sPort.setSerialPortParams(connection.getBaudrate(), connection.getDataBits(), connection.getStopBits(),
                    connection.getParity());
        } catch (final PortInUseException e) {
            sPort = null;
            commPortId = null;
            throw new RuntimeException("端口被占用", e);
        } catch (final UnsupportedCommOperationException e) {
            throw new RuntimeException("不支持的操作", e);
        }

        return sPort;
    }

    @Override
    public void destroy(final SerialPort commPort) {
        if (SerialFactory.log.isInfoEnabled()) {
            SerialFactory.log.info("destroy serial connection object from pool，{}", commPort.getName());
        }
        if (null != commPort) {
            try {
                commPort.getOutputStream().close();
                commPort.getInputStream().close();
                commPort.close();
            } catch (final IOException e) {
                SerialFactory.log.error(e.getMessage(), e);
            }
        }
    }

    @Override
    public void passivateObject(final SerialConnection connection, final PooledObject<SerialPort> pool)
            throws Exception {
        final SerialPort port = pool.getObject();
        port.getInputStream().skip(port.getInputStream().available());
    }

    @Override
    public boolean validateObject(final SerialConnection key, final PooledObject<SerialPort> p) {
        final SerialPort port = p.getObject();
        boolean validated = false;
        if (null != port) {
            validated = true;
        }

        if (SerialFactory.log.isDebugEnabled()) {
            SerialFactory.log.debug("validate serial connection object：{}，{}", key, validated);
        }
        return validated;
    }

}
